#include "modbus.h"
#include "main.h"
#include <stdint.h>
#include "usart.h"
#include "dwt.h"
#include "los_task.h"
#include "app_common.h"
#include "bsp_api.h"
#include "usart.h"
#include "omip_log.h"
//#include "stm32f4xx_hal_def.h"
#define MODBUS_CRC 0xa001
#define UPDATE_FLAG_ADDR   0xFFFFFE

#define ARRAYSIZE(A) sizeof(A) / sizeof(A[0])
#define BAUDRATE 4800

#define PANEL_ADDR 	0x01
#define PANEL_OPCODE_READ 	0x03
#define PANEL_OPCODE_WRITE 	0x06


extern UART_HandleTypeDef huart1;

int rs485_send(uint8_t*pData ,uint16_t iLen) //485发送数据
{
	int iState =uart_send_data(USART1, pData, iLen, iLen*100);
	return iState;
}

int rs485_read(uint8_t*pData ,uint16_t iRecvLen) //485接收数据
{
	int iDataLenInDma =check_uart_data(USART1); //DMA中有多少数据
	if(iDataLenInDma <iRecvLen) return 0; //缓冲区数据不够
	int iDataLen =recv_uart_data(USART1,pData,iRecvLen);
	if(iDataLenInDma >iRecvLen) clear_uart_data(USART1); //把DMA中中剩余的数据清除掉
	return iDataLen;
}

int rs485_read_slave(uint8_t*pData ,uint16_t iRecvLen) //从机485接收数据
{
	int iDataLenInDma = check_uart_data(USART1); //DMA中有多少数据
	if(iDataLenInDma <iRecvLen) return 0; //缓冲区数据不够
	int iDataLen =recv_uart_data(USART1,pData,iRecvLen);
	return iDataLen;
}


unsigned int Get_Crc16(unsigned char *p, unsigned short len) //crc校验
{
	unsigned char i = 0;
	unsigned short tmp = 0xffff;
	while (len > 0)
	{
		tmp ^= *p++;
		while (i < 8)
		{
			if (tmp & 0x0001)
			{
				tmp >>= 1;
				tmp ^= MODBUS_CRC;
			} else {
				tmp >>= 1;
			}
			i++;
		}
		i = 0;
		len--;
	}
  return tmp;
}

int checkModbus(unsigned char *buff, int len) //主设备检查有效性
{
	if(len < 5) return -1; //只处理接收到的读结果
	if((buff[1] & 0x03) != 0x03 && ((buff[1] & 0x06) != 0x06)) return -1; // 03读 06写
	unsigned int iCalcCrc16 = Get_Crc16(buff, len - 2);
	unsigned int iCrc16 = (buff[len - 2] & 0x00ff) | ((buff[len - 1] << 8) & 0xff00);
	if(iCalcCrc16 != iCrc16) return -1;
	return 0;
}

int modbus_req_data_format(modbus_req_t *req_data, UINT8 *buf, UINT16 len)
{
	if(NULL == req_data || NULL == buf) {
		OMIP_LOG_ERROR( "Parameter is null");
		return -1;
	}
	if(sizeof(modbus_req_t) != len) {
		OMIP_LOG_ERROR( "size not match modbus_req_t(%d) != len(%d)", 
							sizeof(modbus_req_t), len);
		return -1;
	}
	memcpy(req_data->buff, buf, len);
	req_data->pkg.reg = ntohs(req_data->pkg.reg);
	req_data->pkg.reg_len = ntohs(req_data->pkg.reg_len);
	UINT32 calc_crc16 = Get_Crc16(buf, len - 2);
	if(req_data->pkg.crc16 != calc_crc16) {
		OMIP_LOG_ERROR( "Check crc error, crc(0x%04x) calc_crc(0x%04x) !!", 
			req_data->pkg.crc16, calc_crc16);
		return -1;
	}
	
	return 0;
}

int modbus_rep_data_format(modbus_rep_t *rep_data, UINT8 *buf, UINT16 len)
{
	if(NULL == rep_data || NULL == buf) {
		OMIP_LOG_ERROR( "Parameter is null");
		return -1;
	}
	if(sizeof(modbus_rep_t) != len) {
		OMIP_LOG_ERROR( "size not match modbus_req_t(%d) != len(%d)", 
							sizeof(modbus_rep_t), len);
		return -1;
	}
	memcpy(rep_data->buff, buf, len);
	rep_data->pkg.data = ntohs(rep_data->pkg.data);
	UINT32 calc_crc16 = Get_Crc16(buf, len - 2);
	if(rep_data->pkg.crc16 != calc_crc16) {
		OMIP_LOG_ERROR( "Check crc error, crc(0x%04x) calc_crc(0x%04x) !!", 
			rep_data->pkg.crc16, calc_crc16);
		return -1;
	}
	return 0;
}

int analyPackage(unsigned char *buf, int len) //分析包，解析
{
	int value =0;
	int ret =checkModbus(buf, len);
	if(ret != 0) {printf("checkModbus error.\r\n"); return -1;}
	if(len == 7)	value = (buf[3] << 8) | buf[4];
	else 			value = (buf[4] << 8) | buf[5];
	return value;
}

void print_binary(unsigned char *data, int len)
{
	int i = 0;
	unsigned char *p_data = data;
	printf("[");
	for(i = 0; i < len; i++) printf("%02x ", p_data[i]);
	printf("]\r\n");
	return;
}

float getCtrlPanelEnvTemp( unsigned char addr) //获得面板环境温度
{
	unsigned char sendbuf[8] = { 0x01, 0x03, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	rs485_send(sendbuf ,(uint16_t) 8);
	LOS_TaskDelay(500); //原版
	int iDataLen = rs485_read(recvbuf,7);
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >=7)
	{
		int value =analyPackage(recvbuf, 7);
		if(value == -1) return INVALID_DATA;
		return (value /10.0f);
	}
	else
	{
		printf("rs485_read failde, ret: %d\r\n",iDataLen);
		return INVALID_DATA;
	}  
}

int getCtrlPanelStatus( unsigned char addr) //获得控制面板状态
{
	unsigned char sendbuf[8] = { 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);
	rs485_send(sendbuf ,(uint16_t) 8);
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	LOS_TaskDelay(500); //原版
	int iDataLen = rs485_read(recvbuf,7);
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >= 7)
	{
		int value = analyPackage(recvbuf, 7);
		if(value == -1) return INVALID_DATA;
		//broadcst_uart_msg(recvbuf, 3); //发送消息给其他vav
		return (value);
	}
	else
	{
		printf("[%s:%d]rs485_read failde, ret: %d\r\n",__FUNCTION__,__LINE__,iDataLen);
		return INVALID_DATA;
	}
}

float getCtrlPanelSetTemp( unsigned char addr) //读取面板设定温度
{
	unsigned char sendbuf[8] = { 0x01, 0x03, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);
	rs485_send(sendbuf ,(uint16_t) 8);
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	LOS_TaskDelay(500); //原版
	int iDataLen =rs485_read(recvbuf,7);
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >=7)
	{
		int value = analyPackage(recvbuf, 7);
		if(value == -1) return INVALID_DATA;
		//broadcst_uart_msg(recvbuf, 2); //发送消息给其他vav
		return (value /10.0f);
	}
	else
	{
		printf("[%s:%d]rs485_read failde, ret: %d\r\n",__FUNCTION__,__LINE__,iDataLen);
		return INVALID_DATA;
	}
}

int getCtrlPanelUnit( unsigned char addr)
{
	unsigned char sendbuf[8] = { 0x01, 0x03, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);
	rs485_send(sendbuf ,(uint16_t) 8);
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	LOS_TaskDelay(500); //原版
	int iDataLen =rs485_read(recvbuf,7);
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >=7)
	{
		int value = analyPackage(recvbuf, 7);
		if(value == -1) return INVALID_DATA;
		//broadcst_uart_msg(recvbuf, 4); //发送消息给其他vav
		return (value);
	}
	else
	{
		printf("[%s:%d]rs485_read failde, ret: %d\r\n",__FUNCTION__,__LINE__,iDataLen);
		return INVALID_DATA;
	}
}

int set_panel_temp( unsigned char addr, float Value) //设定温度
{
	unsigned char sendbuf[8] = { 0x01, 0x06, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	int value = (int)(Value * 10);
	sendbuf[4] = (unsigned char)(value >> 8);
	sendbuf[5] = (unsigned char)(value & 0xff);
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);  
	rs485_send(sendbuf ,(uint16_t) 8);  
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	LOS_TaskDelay(500); //原版
	int iDataLen =rs485_read(recvbuf,8);  
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >=8)
	{
		value = analyPackage(recvbuf, 8);
		if (value == (int)(Value * 10))
		return (0);
	}
	else
	{
		printf("[%s:%d]rs485_read failde, ret: %d\r\n",__FUNCTION__,__LINE__,iDataLen);
		return  -1;
	}
	return  -1;
}

int set_panel_status( unsigned char addr, int iValue) //设定状态
{
	unsigned char sendbuf[8] = { 0x01, 0x06, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00 };
	unsigned char recvbuf[8] = { 0 };
	sendbuf[0] = addr;
	sendbuf[4] = (unsigned char)(iValue >> 8);
	sendbuf[5] = (unsigned char)(iValue & 0xff);
	unsigned int iCrc16 = Get_Crc16(sendbuf, ARRAYSIZE(sendbuf) - 2);
	sendbuf[6] = (unsigned char)(iCrc16 & 0xff);
	sendbuf[7] = (unsigned char)((iCrc16 >> 8) & 0xff);
	rs485_send(sendbuf ,(uint16_t) 8);
	//printf("send"); print_binary(sendbuf, ARRAYSIZE(sendbuf));
	LOS_TaskDelay(500); //原版
	int iDataLen =rs485_read(recvbuf,8);
	//printf("recv"); print_binary(recvbuf, ARRAYSIZE(recvbuf));
	if(iDataLen >=8)
	{
		int value = analyPackage(recvbuf, 8);
		if (value == (int)(iValue))
		return (0);
	}
	else
	{
		printf("[%s:%d]rs485_read failde, ret: %d\r\n",__FUNCTION__,__LINE__,iDataLen);
		return  -1;
	}
	return  -1;
}

void slave_uart_recv_process(USART_TypeDef *pUart)
{
	uint16_t recvlen =0;
	int len = 0;
	uint8_t recvbuf[64] ={0};
	modbus_req_t req_data;
	modbus_rep_t rep_data;
	int status = MOD_REQ_ADDR;

	while(1) 
	{
		LOS_TaskDelay(20);
		if(status == MOD_REQ_ADDR && check_uart_data(pUart) < 15) {
			return;
		}
		
		//OMIP_LOG_DEBUG("status:%d, recvlen:%d", status, recvlen);
		switch (status)
		{
		case MOD_REQ_ADDR: //找面板地址01 03报文头
			len = recv_uart_data(pUart, recvbuf, 1);
			recvlen += len;
			if(recvlen < 1) {
				status = MOD_BUF_CLEAR;
				break;
			}
			if(recvbuf[0] != PANEL_ADDR) {
				status = MOD_BUF_CLEAR;
				break;
			}
			status = MOD_REQ_OPCODE;
			break;
		case MOD_REQ_OPCODE: //找操作码 03
			len = recv_uart_data(pUart, recvbuf+1, 1);
			recvlen += len;
			if(recvlen < 2) {
				status = MOD_BUF_CLEAR;
				break;
			}
			if(recvbuf[1] == PANEL_OPCODE_READ
				|| recvbuf[1] == PANEL_OPCODE_WRITE) {
				status = MOD_REQ_DATA;
				break;
			}
			status = MOD_BUF_CLEAR;
			break;
		case MOD_REQ_DATA: //解析请求
			len = recv_uart_data(pUart, recvbuf+recvlen, 8-recvlen);
			recvlen += len;
			if(recvlen < 8) {
				break;
			}
			//printf("recv[%d]", sizeof(req_data)); print_binary(recvbuf, sizeof(req_data));
			if (0 != modbus_req_data_format(&req_data, recvbuf, 8)) {
				status = MOD_DMA_CLEAR_END;
				break;
			}
			status = MOD_REP_PKG;
			break;
			
		case MOD_REP_PKG:  //解析响应包
			if(req_data.pkg.opcode == PANEL_OPCODE_READ){
				len = recv_uart_data(pUart, recvbuf+recvlen, 15-recvlen);
				recvlen += len;
				if(recvlen < 15) {
					status = MOD_DMA_CLEAR_END;
					break;
				}
				//printf("rep[%d]", sizeof(rep_data)); print_binary(recvbuf+8, 7);
				if(0 != modbus_rep_data_format(&rep_data, recvbuf+8, 7)) {
					sync_panel_err(req_data.pkg.reg, -1);
					status = MOD_DMA_CLEAR_END;
					break;
				}
				OMIP_LOG_DEBUG( "data:%d", rep_data.pkg.data);
				sync_panel_data(req_data.pkg.reg, rep_data.pkg.data);
				status = MOD_ANALY_END;
				break;
			}
			else if(req_data.pkg.opcode == PANEL_OPCODE_WRITE){
				len = recv_uart_data(pUart, recvbuf+recvlen, 16-recvlen);
				recvlen += len;
				if(recvlen < 16) {
					status = MOD_DMA_CLEAR_END;
					break;
				}
				if(-1 == analyPackage(recvbuf+8, 8)) {
					status = MOD_DMA_CLEAR_END;
					break;
				}
			}
			status = MOD_DMA_CLEAR_END;
			break;
		case MOD_BUF_CLEAR:
			memset(recvbuf, 0, sizeof(recvbuf));
			recvlen = 0;
			status = MOD_REQ_ADDR;
			break;
		case MOD_DMA_CLEAR_END:
			OMIP_LOG_DEBUG( "Clear usart DMA!");
			clear_uart_data(pUart);
			return;
		case MOD_ANALY_END:
			return;
		default:
			OMIP_LOG_ERROR( "Unknown status:%d, recvlen:%d", status, recvlen);
			return;
		}
	
	}
}











